package com.junxonline.instant.admin.aspect;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.junxonline.instant.dao.entity.model.config.*;
import com.junxonline.instant.dao.mapper.config.*;
import com.junxonline.instant.common.annotation.DataScope;
import com.junxonline.instant.common.enumeration.DataScopeEnum;
import com.junxonline.instant.common.util.admin.TokenUtils;
import lombok.extern.log4j.Log4j2;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 数据权限切面类
 *
 * @author JunX
 * @date 2021-12-28
 */
@Log4j2
@Aspect
@Component
public class DataScopeAspect {

    @Autowired
    private TokenUtils tokenUtils;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserRoleMapper userRoleMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private RoleOrganizationMapper roleOrganizationMapper;

    @Autowired
    private OrganizationMapper organizationMapper;

    /**
     * 数据权限过滤关键字
     */
    public static final String DATA_SCOPE = "dataScopeParams";

    /**
     * 定义切入点为标识了注解@DataScope的方法
     */
    @Pointcut(value = "@annotation(dataScope)")
    public void dataScopeService(DataScope dataScope) {

    }

    /**
     * 前置通知
     *
     * @param joinPoint 切入点
     * @param dataScope 自定义数据权限注解
     */
    @Before(value = "dataScopeService(dataScope)")
    public void before(JoinPoint joinPoint, DataScope dataScope) {
        dataScopeHandler(joinPoint, dataScope);
    }

    /**
     * 后置通知
     *
     * @param joinPoint 切入点
     * @param dataScope 自定义数据权限注解
     */
    @AfterReturning(value = "dataScopeService(dataScope)")
    public void afterReturning(JoinPoint joinPoint, DataScope dataScope) {

    }

    /**
     * 异常通知
     *
     * @param joinPoint 切入点
     * @param dataScope 自定义数据权限注解
     * @param e         异常
     */
    @AfterThrowing(value = "dataScopeService(dataScope)", throwing = "e")
    public void afterThrowing(JoinPoint joinPoint, DataScope dataScope, Exception e) {

    }

    /**
     * 数据权限处理
     *
     * @param joinPoint 切入点
     * @param dataScope 自定义数据权限注解
     */
    private void dataScopeHandler(JoinPoint joinPoint, DataScope dataScope) {
        // 获取当前的用户
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        String token = request.getHeader("Authorization");
        if (!StrUtil.isBlank(token)) {
            Long userId = tokenUtils.getUserId(token);
            User user = userMapper.selectById(userId);
            if (user != null) {
                List<UserRole> userRoles = userRoleMapper.selectList(new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId, userId));
                dataScopeFilter(joinPoint, dataScope.isExistCreateId(), dataScope.isSelfSkip(), user, userRoles);
            }
        }
    }

    /**
     * 数据权限处理
     *
     * @param joinPoint       切入点
     * @param isExistCreateId 是否有create_id字段
     * @param isSelfSkip 当数据权限类型为'仅自己'时是否跳过数据过滤
     * @param user            当前用户
     * @param userRoles       用户拥有的角色
     */
    private void dataScopeFilter(JoinPoint joinPoint, boolean isExistCreateId, boolean isSelfSkip, User user, List<UserRole> userRoles) {
        for (Object params : joinPoint.getArgs()) {
            if (params instanceof QueryWrapper) {
                QueryWrapper<Object> wrapper = (QueryWrapper<Object>) params;
                wrapper.and(wp -> {
                    for (UserRole userRole : userRoles) {
                        Role role = roleMapper.selectById(userRole.getRoleId());
                        if (role != null) {
                            // 获取角色的数据权限类型
                            Integer dataScope = role.getDataScope();
                            // 全部
                            if (dataScope.equals(DataScopeEnum.ALL.getValue())) {
                                wp.clear();
                                wp.last("1 = 1");
                                break;
                            }
                            // 自定义
                            else if (dataScope.equals(DataScopeEnum.CUSTOM.getValue())) {
                                List<RoleOrganization> roleOrganizations = roleOrganizationMapper.selectList(new QueryWrapper<RoleOrganization>().eq("role_id", role.getId()));
                                List<Long> organizationIds = roleOrganizations.stream().map(RoleOrganization::getOrganizationId).collect(Collectors.toList());
                                wp.in("t.organization_id", organizationIds).or();
                            }
                            // 本级
                            else if (dataScope.equals(DataScopeEnum.ORGANIZATION.getValue())) {
                                wp.eq("t.organization_id", user.getOrganizationId()).or();
                            }
                            // 仅自己
                            else if (dataScope.equals(DataScopeEnum.SELF.getValue())) {
                                // 当跳过时则直接将数据权限设定为本级
                                if (isSelfSkip) {
                                    wp.eq("t.organization_id", user.getOrganizationId()).or();
                                }
                                // 不跳过时正常拦截
                                else {
                                    if (isExistCreateId) {
                                        wp.eq("t.create_id", user.getId()).or();
                                    } else {
                                        wp.eq("t.organization_id", -1).or();
                                    }
                                }
                            }
                            // 默认策略 本级及下级
                            else {
                                Set<Long> organizationIds = new HashSet<>();
                                organizationIds.add(user.getOrganizationId());
                                List<Organization> childrenOrganizations = organizationMapper.queryChildren(user.getOrganizationId());
                                // 解析树形数据为平级结构
                                treeToFlat(organizationIds, childrenOrganizations);
                                wp.in("t.organization_id", organizationIds).or();
                            }
                        }
                    }
                });
            }
        }
    }

    /**
     * 树形结构转为扁平结构
     *
     * @param organizationIds 扁平集合
     * @param organizations   树形集合
     */
    private void treeToFlat(Set<Long> organizationIds, List<Organization> organizations) {
        for (Organization organization : organizations) {
            organizationIds.add(organization.getId());
            if (organization.getChildren() != null && organization.getChildren().size() > 0) {
                this.treeToFlat(organizationIds, organization.getChildren());
            }
        }
    }

}
